get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/88267/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 88267,
    "url": "http://patches.dpdk.org/api/patches/88267/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20210226200136.4265-1-cristian.dumitrescu@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210226200136.4265-1-cristian.dumitrescu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210226200136.4265-1-cristian.dumitrescu@intel.com",
    "date": "2021-02-26T20:01:36",
    "name": "pipeline: add register array support to SWX pipeline",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "fc24dbe91af5e9eabffbe796a8d11dff72125891",
    "submitter": {
        "id": 19,
        "url": "http://patches.dpdk.org/api/people/19/?format=api",
        "name": "Cristian Dumitrescu",
        "email": "cristian.dumitrescu@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20210226200136.4265-1-cristian.dumitrescu@intel.com/mbox/",
    "series": [
        {
            "id": 15398,
            "url": "http://patches.dpdk.org/api/series/15398/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=15398",
            "date": "2021-02-26T20:01:36",
            "name": "pipeline: add register array support to SWX pipeline",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/15398/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/88267/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/88267/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id CD893A034F;\n\tFri, 26 Feb 2021 21:01:41 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 3F6B640A4B;\n\tFri, 26 Feb 2021 21:01:41 +0100 (CET)",
            "from mga05.intel.com (mga05.intel.com [192.55.52.43])\n by mails.dpdk.org (Postfix) with ESMTP id 9BB65407FF\n for <dev@dpdk.org>; Fri, 26 Feb 2021 21:01:39 +0100 (CET)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 26 Feb 2021 12:01:38 -0800",
            "from silpixa00400573.ir.intel.com (HELO\n silpixa00400573.ger.corp.intel.com) ([10.237.223.107])\n by orsmga002.jf.intel.com with ESMTP; 26 Feb 2021 12:01:36 -0800"
        ],
        "IronPort-SDR": [
            "\n O29Uf17vufeY9lJLxUMLJrhLSkW/6kPz6kf30nmsATzaCX9r8OHO+Z7KINZ5vip2+EgVRKGZKH\n WSGsdX2pO4Cg==",
            "\n P3ZvZ/aOyBzULO7WVaRdPy4byr/taUbsYOyEldcI1j/dxjkQ7mKVpF06vBTAN+PA79XKf3yvcM\n gzSF19UrU0sQ=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6000,8403,9907\"; a=\"270961657\"",
            "E=Sophos;i=\"5.81,209,1610438400\"; d=\"scan'208\";a=\"270961657\"",
            "E=Sophos;i=\"5.81,209,1610438400\"; d=\"scan'208\";a=\"382132934\""
        ],
        "X-ExtLoop1": "1",
        "From": "Cristian Dumitrescu <cristian.dumitrescu@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Fri, 26 Feb 2021 20:01:36 +0000",
        "Message-Id": "<20210226200136.4265-1-cristian.dumitrescu@intel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "Subject": "[dpdk-dev] [PATCH] pipeline: add register array support to SWX\n pipeline",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Register arrays are stateful objects that can be read & modified by\nboth the data plane and the control plane, as opposed to tables, which\nare read-only for data plane. One key use-case is the implementation\nof stats counters.\n\nSigned-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>\n---\n examples/pipeline/cli.c                     |  125 ++\n lib/librte_pipeline/rte_swx_ctl.h           |   79 +\n lib/librte_pipeline/rte_swx_pipeline.c      | 1712 +++++++++++++++++--\n lib/librte_pipeline/rte_swx_pipeline.h      |   21 +\n lib/librte_pipeline/rte_swx_pipeline_spec.c |   91 +\n lib/librte_pipeline/version.map             |    6 +\n 6 files changed, 1855 insertions(+), 179 deletions(-)",
    "diff": "diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c\nindex 30c2dd34d..cdf8f13f3 100644\n--- a/examples/pipeline/cli.c\n+++ b/examples/pipeline/cli.c\n@@ -1009,6 +1009,105 @@ cmd_pipeline_table_update(char **tokens,\n \t\tfclose(file_default);\n }\n \n+static const char cmd_pipeline_regrd_help[] =\n+\"pipeline <pipeline_name> regrd <register_array_name> <index>\\n\";\n+\n+static void\n+cmd_pipeline_regrd(char **tokens,\n+\tuint32_t n_tokens,\n+\tchar *out,\n+\tsize_t out_size,\n+\tvoid *obj)\n+{\n+\tstruct pipeline *p;\n+\tconst char *name;\n+\tuint64_t value;\n+\tuint32_t idx;\n+\tint status;\n+\n+\tif (n_tokens != 5) {\n+\t\tsnprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);\n+\t\treturn;\n+\t}\n+\n+\tp = pipeline_find(obj, tokens[1]);\n+\tif (!p || !p->ctl) {\n+\t\tsnprintf(out, out_size, MSG_ARG_INVALID, \"pipeline_name\");\n+\t\treturn;\n+\t}\n+\n+\tif (strcmp(tokens[2], \"regrd\")) {\n+\t\tsnprintf(out, out_size, MSG_ARG_NOT_FOUND, \"regrd\");\n+\t\treturn;\n+\t}\n+\n+\tname = tokens[3];\n+\n+\tif (parser_read_uint32(&idx, tokens[4])) {\n+\t\tsnprintf(out, out_size, MSG_ARG_INVALID, \"index\");\n+\t\treturn;\n+\t}\n+\n+\tstatus = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);\n+\tif (status) {\n+\t\tsnprintf(out, out_size, \"Command failed.\\n\");\n+\t\treturn;\n+\t}\n+\n+\tsnprintf(out, out_size, \"0x%\" PRIx64 \"\\n\", value);\n+}\n+\n+static const char cmd_pipeline_regwr_help[] =\n+\"pipeline <pipeline_name> regwr <register_array_name> <index> <value>\\n\";\n+\n+static void\n+cmd_pipeline_regwr(char **tokens,\n+\tuint32_t n_tokens,\n+\tchar *out,\n+\tsize_t out_size,\n+\tvoid *obj)\n+{\n+\tstruct pipeline *p;\n+\tconst char *name;\n+\tuint64_t value;\n+\tuint32_t idx;\n+\tint status;\n+\n+\tif (n_tokens != 6) {\n+\t\tsnprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);\n+\t\treturn;\n+\t}\n+\n+\tp = pipeline_find(obj, tokens[1]);\n+\tif (!p || !p->ctl) {\n+\t\tsnprintf(out, out_size, MSG_ARG_INVALID, \"pipeline_name\");\n+\t\treturn;\n+\t}\n+\n+\tif (strcmp(tokens[2], \"regwr\")) {\n+\t\tsnprintf(out, out_size, MSG_ARG_NOT_FOUND, \"regwr\");\n+\t\treturn;\n+\t}\n+\n+\tname = tokens[3];\n+\n+\tif (parser_read_uint32(&idx, tokens[4])) {\n+\t\tsnprintf(out, out_size, MSG_ARG_INVALID, \"index\");\n+\t\treturn;\n+\t}\n+\n+\tif (parser_read_uint64(&value, tokens[5])) {\n+\t\tsnprintf(out, out_size, MSG_ARG_INVALID, \"value\");\n+\t\treturn;\n+\t}\n+\n+\tstatus = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);\n+\tif (status) {\n+\t\tsnprintf(out, out_size, \"Command failed.\\n\");\n+\t\treturn;\n+\t}\n+}\n+\n static const char cmd_pipeline_stats_help[] =\n \"pipeline <pipeline_name> stats\\n\";\n \n@@ -1202,6 +1301,8 @@ cmd_help(char **tokens,\n \t\t\t\"\\tpipeline port out\\n\"\n \t\t\t\"\\tpipeline build\\n\"\n \t\t\t\"\\tpipeline table update\\n\"\n+\t\t\t\"\\tpipeline regrd\\n\"\n+\t\t\t\"\\tpipeline regwr\\n\"\n \t\t\t\"\\tpipeline stats\\n\"\n \t\t\t\"\\tthread pipeline enable\\n\"\n \t\t\t\"\\tthread pipeline disable\\n\\n\");\n@@ -1254,6 +1355,18 @@ cmd_help(char **tokens,\n \t\treturn;\n \t}\n \n+\tif ((strcmp(tokens[0], \"pipeline\") == 0) &&\n+\t\t(n_tokens == 2) && (strcmp(tokens[1], \"regrd\") == 0)) {\n+\t\tsnprintf(out, out_size, \"\\n%s\\n\", cmd_pipeline_regrd_help);\n+\t\treturn;\n+\t}\n+\n+\tif ((strcmp(tokens[0], \"pipeline\") == 0) &&\n+\t\t(n_tokens == 2) && (strcmp(tokens[1], \"regwr\") == 0)) {\n+\t\tsnprintf(out, out_size, \"\\n%s\\n\", cmd_pipeline_regwr_help);\n+\t\treturn;\n+\t}\n+\n \tif ((strcmp(tokens[0], \"pipeline\") == 0) &&\n \t\t(n_tokens == 2) && (strcmp(tokens[1], \"stats\") == 0)) {\n \t\tsnprintf(out, out_size, \"\\n%s\\n\", cmd_pipeline_stats_help);\n@@ -1356,6 +1469,18 @@ cli_process(char *in, char *out, size_t out_size, void *obj)\n \t\t\treturn;\n \t\t}\n \n+\t\tif ((n_tokens >= 3) &&\n+\t\t\t(strcmp(tokens[2], \"regrd\") == 0)) {\n+\t\t\tcmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj);\n+\t\t\treturn;\n+\t\t}\n+\n+\t\tif ((n_tokens >= 3) &&\n+\t\t\t(strcmp(tokens[2], \"regwr\") == 0)) {\n+\t\t\tcmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj);\n+\t\t\treturn;\n+\t\t}\n+\n \t\tif ((n_tokens >= 3) &&\n \t\t\t(strcmp(tokens[2], \"stats\") == 0)) {\n \t\t\tcmd_pipeline_stats(tokens, n_tokens, out, out_size,\ndiff --git a/lib/librte_pipeline/rte_swx_ctl.h b/lib/librte_pipeline/rte_swx_ctl.h\nindex 530671db1..c0a55c6f0 100644\n--- a/lib/librte_pipeline/rte_swx_ctl.h\n+++ b/lib/librte_pipeline/rte_swx_ctl.h\n@@ -46,6 +46,9 @@ struct rte_swx_ctl_pipeline_info {\n \n \t/** Number of tables. */\n \tuint32_t n_tables;\n+\n+\t/** Number of register arrays. */\n+\tuint32_t n_regarrays;\n };\n \n /**\n@@ -557,6 +560,82 @@ rte_swx_ctl_pipeline_table_fprintf(FILE *f,\n \t\t\t\t   struct rte_swx_ctl_pipeline *ctl,\n \t\t\t\t   const char *table_name);\n \n+/*\n+ * Register Array Query API.\n+ */\n+\n+/** Register array info. */\n+struct rte_swx_ctl_regarray_info {\n+\t/** Register array name. */\n+\tchar name[RTE_SWX_CTL_NAME_SIZE];\n+\n+\t/** Register array size. */\n+\tuint32_t size;\n+};\n+\n+/**\n+ * Register array info get\n+ *\n+ * @param[in] p\n+ *   Pipeline handle.\n+ * @param[in] regarray_id\n+ *   Register array ID (0 .. *n_regarrays* - 1).\n+ * @param[out] regarray\n+ *   Register array info.\n+ * @return\n+ *   0 on success or the following error codes otherwise:\n+ *   -EINVAL: Invalid argument.\n+ */\n+__rte_experimental\n+int\n+rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p,\n+\t\t\t      uint32_t regarray_id,\n+\t\t\t      struct rte_swx_ctl_regarray_info *regarray);\n+\n+/**\n+ * Register read\n+ *\n+ * @param[in] p\n+ *   Pipeline handle.\n+ * @param[in] regarray_name\n+ *   Register array name.\n+ * @param[in] regarray_index\n+ *   Register index within the array (0 .. *size* - 1).\n+ * @param[out] value\n+ *   Current register value.\n+ * @return\n+ *   0 on success or the following error codes otherwise:\n+ *   -EINVAL: Invalid argument.\n+ */\n+__rte_experimental\n+int\n+rte_swx_ctl_pipeline_regarray_read(struct rte_swx_pipeline *p,\n+\t\t\t\t   const char *regarray_name,\n+\t\t\t\t   uint32_t regarray_index,\n+\t\t\t\t   uint64_t *value);\n+\n+/**\n+ * Register write\n+ *\n+ * @param[in] p\n+ *   Pipeline handle.\n+ * @param[in] regarray_name\n+ *   Register array name.\n+ * @param[in] regarray_index\n+ *   Register index within the array (0 .. *size* - 1).\n+ * @param[in] value\n+ *   Value to be written to the register.\n+ * @return\n+ *   0 on success or the following error codes otherwise:\n+ *   -EINVAL: Invalid argument.\n+ */\n+__rte_experimental\n+int\n+rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p,\n+\t\t\t\t   const char *regarray_name,\n+\t\t\t\t   uint32_t regarray_index,\n+\t\t\t\t   uint64_t value);\n+\n /**\n  * Pipeline control free\n  *\ndiff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c\nindex eaaed7a0a..cb7ee48cc 100644\n--- a/lib/librte_pipeline/rte_swx_pipeline.c\n+++ b/lib/librte_pipeline/rte_swx_pipeline.c\n@@ -361,6 +361,53 @@ enum instruction_type {\n \tINSTR_ALU_SHR_MI, /* dst = MEF, src = I */\n \tINSTR_ALU_SHR_HI, /* dst = H, src = I */\n \n+\t/* regprefetch REGARRAY index\n+\t * prefetch REGARRAY[index]\n+\t * index = HMEFTI\n+\t */\n+\tINSTR_REGPREFETCH_RH, /* index = H */\n+\tINSTR_REGPREFETCH_RM, /* index = MEFT */\n+\tINSTR_REGPREFETCH_RI, /* index = I */\n+\n+\t/* regrd dst REGARRAY index\n+\t * dst = REGARRAY[index]\n+\t * dst = HMEF, index = HMEFTI\n+\t */\n+\tINSTR_REGRD_HRH, /* dst = H, index = H */\n+\tINSTR_REGRD_HRM, /* dst = H, index = MEFT */\n+\tINSTR_REGRD_HRI, /* dst = H, index = I */\n+\tINSTR_REGRD_MRH, /* dst = MEF, index = H */\n+\tINSTR_REGRD_MRM, /* dst = MEF, index = MEFT */\n+\tINSTR_REGRD_MRI, /* dst = MEF, index = I */\n+\n+\t/* regwr REGARRAY index src\n+\t * REGARRAY[index] = src\n+\t * index = HMEFTI, src = HMEFTI\n+\t */\n+\tINSTR_REGWR_RHH, /* index = H, src = H */\n+\tINSTR_REGWR_RHM, /* index = H, src = MEFT */\n+\tINSTR_REGWR_RHI, /* index = H, src = I */\n+\tINSTR_REGWR_RMH, /* index = MEFT, src = H */\n+\tINSTR_REGWR_RMM, /* index = MEFT, src = MEFT */\n+\tINSTR_REGWR_RMI, /* index = MEFT, src = I */\n+\tINSTR_REGWR_RIH, /* index = I, src = H */\n+\tINSTR_REGWR_RIM, /* index = I, src = MEFT */\n+\tINSTR_REGWR_RII, /* index = I, src = I */\n+\n+\t/* regadd REGARRAY index src\n+\t * REGARRAY[index] += src\n+\t * index = HMEFTI, src = HMEFTI\n+\t */\n+\tINSTR_REGADD_RHH, /* index = H, src = H */\n+\tINSTR_REGADD_RHM, /* index = H, src = MEFT */\n+\tINSTR_REGADD_RHI, /* index = H, src = I */\n+\tINSTR_REGADD_RMH, /* index = MEFT, src = H */\n+\tINSTR_REGADD_RMM, /* index = MEFT, src = MEFT */\n+\tINSTR_REGADD_RMI, /* index = MEFT, src = I */\n+\tINSTR_REGADD_RIH, /* index = I, src = H */\n+\tINSTR_REGADD_RIM, /* index = I, src = MEFT */\n+\tINSTR_REGADD_RII, /* index = I, src = I */\n+\n \t/* table TABLE */\n \tINSTR_TABLE,\n \n@@ -495,6 +542,21 @@ struct instr_dst_src {\n \t};\n };\n \n+struct instr_regarray {\n+\tuint8_t regarray_id;\n+\tuint8_t pad[3];\n+\n+\tunion {\n+\t\tstruct instr_operand idx;\n+\t\tuint32_t idx_val;\n+\t};\n+\n+\tunion {\n+\t\tstruct instr_operand dstsrc;\n+\t\tuint64_t dstsrc_val;\n+\t};\n+};\n+\n struct instr_dma {\n \tstruct {\n \t\tuint8_t header_id[8];\n@@ -529,6 +591,7 @@ struct instruction {\n \t\tstruct instr_io io;\n \t\tstruct instr_hdr_validity valid;\n \t\tstruct instr_dst_src mov;\n+\t\tstruct instr_regarray regarray;\n \t\tstruct instr_dma dma;\n \t\tstruct instr_dst_src alu;\n \t\tstruct instr_table table;\n@@ -608,6 +671,23 @@ struct table_runtime {\n \tuint8_t **key;\n };\n \n+/*\n+ * Register array.\n+ */\n+struct regarray {\n+\tTAILQ_ENTRY(regarray) node;\n+\tchar name[RTE_SWX_NAME_SIZE];\n+\tuint32_t size;\n+\tuint32_t id;\n+};\n+\n+TAILQ_HEAD(regarray_tailq, regarray);\n+\n+struct regarray_runtime {\n+\tuint64_t *regarray;\n+\tuint32_t size_mask;\n+};\n+\n /*\n  * Pipeline.\n  */\n@@ -983,11 +1063,13 @@ struct rte_swx_pipeline {\n \tstruct action_tailq actions;\n \tstruct table_type_tailq table_types;\n \tstruct table_tailq tables;\n+\tstruct regarray_tailq regarrays;\n \n \tstruct port_in_runtime *in;\n \tstruct port_out_runtime *out;\n \tstruct instruction **action_instructions;\n \tstruct rte_swx_table_state *table_state;\n+\tstruct regarray_runtime *regarray_runtime;\n \tstruct instruction *instructions;\n \tstruct thread threads[RTE_SWX_PIPELINE_THREADS_MAX];\n \n@@ -998,6 +1080,7 @@ struct rte_swx_pipeline {\n \tuint32_t n_extern_funcs;\n \tuint32_t n_actions;\n \tuint32_t n_tables;\n+\tuint32_t n_regarrays;\n \tuint32_t n_headers;\n \tuint32_t thread_id;\n \tuint32_t port_id;\n@@ -4622,252 +4705,1278 @@ instr_alu_ckadd_struct_exec(struct rte_swx_pipeline *p)\n }\n \n /*\n- * jmp.\n+ * regarray.\n  */\n-static struct action *\n-action_find(struct rte_swx_pipeline *p, const char *name);\n-\n-static int\n-instr_jmp_translate(struct rte_swx_pipeline *p __rte_unused,\n-\t\t    struct action *action __rte_unused,\n-\t\t    char **tokens,\n-\t\t    int n_tokens,\n-\t\t    struct instruction *instr,\n-\t\t    struct instruction_data *data)\n-{\n-\tCHECK(n_tokens == 2, EINVAL);\n-\n-\tstrcpy(data->jmp_label, tokens[1]);\n-\n-\tinstr->type = INSTR_JMP;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\treturn 0;\n-}\n+static struct regarray *\n+regarray_find(struct rte_swx_pipeline *p, const char *name);\n \n static int\n-instr_jmp_valid_translate(struct rte_swx_pipeline *p,\n-\t\t\t  struct action *action __rte_unused,\n-\t\t\t  char **tokens,\n-\t\t\t  int n_tokens,\n-\t\t\t  struct instruction *instr,\n-\t\t\t  struct instruction_data *data)\n+instr_regprefetch_translate(struct rte_swx_pipeline *p,\n+\t\t      struct action *action,\n+\t\t      char **tokens,\n+\t\t      int n_tokens,\n+\t\t      struct instruction *instr,\n+\t\t      struct instruction_data *data __rte_unused)\n {\n-\tstruct header *h;\n+\tchar *regarray = tokens[1], *idx = tokens[2];\n+\tstruct regarray *r;\n+\tstruct field *fidx;\n+\tuint32_t idx_struct_id, idx_val;\n \n \tCHECK(n_tokens == 3, EINVAL);\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\tr = regarray_find(p, regarray);\n+\tCHECK(r, EINVAL);\n+\n+\t/* REGPREFETCH_RH, REGPREFETCH_RM. */\n+\tfidx = struct_field_parse(p, action, idx, &idx_struct_id);\n+\tif (fidx) {\n+\t\tinstr->type = INSTR_REGPREFETCH_RM;\n+\t\tif (idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGPREFETCH_RH;\n+\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc_val = 0; /* Unused. */\n+\t\treturn 0;\n+\t}\n \n-\th = header_parse(p, tokens[2]);\n-\tCHECK(h, EINVAL);\n+\t/* REGPREFETCH_RI. */\n+\tidx_val = strtoul(idx, &idx, 0);\n+\tCHECK(!idx[0], EINVAL);\n \n-\tinstr->type = INSTR_JMP_VALID;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\tinstr->jmp.header_id = h->id;\n+\tinstr->type = INSTR_REGPREFETCH_RI;\n+\tinstr->regarray.regarray_id = r->id;\n+\tinstr->regarray.idx_val = idx_val;\n+\tinstr->regarray.dstsrc_val = 0; /* Unused. */\n \treturn 0;\n }\n \n static int\n-instr_jmp_invalid_translate(struct rte_swx_pipeline *p,\n-\t\t\t    struct action *action __rte_unused,\n-\t\t\t    char **tokens,\n-\t\t\t    int n_tokens,\n-\t\t\t    struct instruction *instr,\n-\t\t\t    struct instruction_data *data)\n+instr_regrd_translate(struct rte_swx_pipeline *p,\n+\t\t      struct action *action,\n+\t\t      char **tokens,\n+\t\t      int n_tokens,\n+\t\t      struct instruction *instr,\n+\t\t      struct instruction_data *data __rte_unused)\n {\n-\tstruct header *h;\n+\tchar *dst = tokens[1], *regarray = tokens[2], *idx = tokens[3];\n+\tstruct regarray *r;\n+\tstruct field *fdst, *fidx;\n+\tuint32_t dst_struct_id, idx_struct_id, idx_val;\n \n-\tCHECK(n_tokens == 3, EINVAL);\n+\tCHECK(n_tokens == 4, EINVAL);\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\tr = regarray_find(p, regarray);\n+\tCHECK(r, EINVAL);\n \n-\th = header_parse(p, tokens[2]);\n-\tCHECK(h, EINVAL);\n+\tfdst = struct_field_parse(p, NULL, dst, &dst_struct_id);\n+\tCHECK(fdst, EINVAL);\n \n-\tinstr->type = INSTR_JMP_INVALID;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\tinstr->jmp.header_id = h->id;\n-\treturn 0;\n-}\n+\t/* REGRD_HRH, REGRD_HRM, REGRD_MRH, REGRD_MRM. */\n+\tfidx = struct_field_parse(p, action, idx, &idx_struct_id);\n+\tif (fidx) {\n+\t\tinstr->type = INSTR_REGRD_MRM;\n+\t\tif (dst[0] == 'h' && idx[0] == 'm')\n+\t\t\tinstr->type = INSTR_REGRD_HRM;\n+\t\tif (dst[0] == 'm' && idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGRD_MRH;\n+\t\tif (dst[0] == 'h' && idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGRD_HRH;\n+\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc.struct_id = (uint8_t)dst_struct_id;\n+\t\tinstr->regarray.dstsrc.n_bits = fdst->n_bits;\n+\t\tinstr->regarray.dstsrc.offset = fdst->offset / 8;\n+\t\treturn 0;\n+\t}\n \n-static int\n-instr_jmp_hit_translate(struct rte_swx_pipeline *p __rte_unused,\n-\t\t\tstruct action *action,\n-\t\t\tchar **tokens,\n-\t\t\tint n_tokens,\n-\t\t\tstruct instruction *instr,\n-\t\t\tstruct instruction_data *data)\n-{\n-\tCHECK(!action, EINVAL);\n-\tCHECK(n_tokens == 2, EINVAL);\n+\t/* REGRD_MRI, REGRD_HRI. */\n+\tidx_val = strtoul(idx, &idx, 0);\n+\tCHECK(!idx[0], EINVAL);\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\tinstr->type = INSTR_REGRD_MRI;\n+\tif (dst[0] == 'h')\n+\t\tinstr->type = INSTR_REGRD_HRI;\n \n-\tinstr->type = INSTR_JMP_HIT;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->regarray.regarray_id = r->id;\n+\tinstr->regarray.idx_val = idx_val;\n+\tinstr->regarray.dstsrc.struct_id = (uint8_t)dst_struct_id;\n+\tinstr->regarray.dstsrc.n_bits = fdst->n_bits;\n+\tinstr->regarray.dstsrc.offset = fdst->offset / 8;\n \treturn 0;\n }\n \n static int\n-instr_jmp_miss_translate(struct rte_swx_pipeline *p __rte_unused,\n-\t\t\t struct action *action,\n-\t\t\t char **tokens,\n-\t\t\t int n_tokens,\n-\t\t\t struct instruction *instr,\n-\t\t\t struct instruction_data *data)\n+instr_regwr_translate(struct rte_swx_pipeline *p,\n+\t\t      struct action *action,\n+\t\t      char **tokens,\n+\t\t      int n_tokens,\n+\t\t      struct instruction *instr,\n+\t\t      struct instruction_data *data __rte_unused)\n {\n-\tCHECK(!action, EINVAL);\n-\tCHECK(n_tokens == 2, EINVAL);\n+\tchar *regarray = tokens[1], *idx = tokens[2], *src = tokens[3];\n+\tstruct regarray *r;\n+\tstruct field *fidx, *fsrc;\n+\tuint64_t src_val;\n+\tuint32_t idx_struct_id, idx_val, src_struct_id;\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\tCHECK(n_tokens == 4, EINVAL);\n \n-\tinstr->type = INSTR_JMP_MISS;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\treturn 0;\n-}\n+\tr = regarray_find(p, regarray);\n+\tCHECK(r, EINVAL);\n \n-static int\n-instr_jmp_action_hit_translate(struct rte_swx_pipeline *p,\n-\t\t\t       struct action *action,\n-\t\t\t       char **tokens,\n-\t\t\t       int n_tokens,\n-\t\t\t       struct instruction *instr,\n-\t\t\t       struct instruction_data *data)\n-{\n-\tstruct action *a;\n+\t/* REGWR_RHH, REGWR_RHM, REGWR_RMH, REGWR_RMM. */\n+\tfidx = struct_field_parse(p, action, idx, &idx_struct_id);\n+\tfsrc = struct_field_parse(p, action, src, &src_struct_id);\n+\tif (fidx && fsrc) {\n+\t\tinstr->type = INSTR_REGWR_RMM;\n+\t\tif (idx[0] == 'h' && src[0] == 'm')\n+\t\t\tinstr->type = INSTR_REGWR_RHM;\n+\t\tif (idx[0] == 'm' && src[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGWR_RMH;\n+\t\tif (idx[0] == 'h' && src[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGWR_RHH;\n+\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;\n+\t\tinstr->regarray.dstsrc.n_bits = fsrc->n_bits;\n+\t\tinstr->regarray.dstsrc.offset = fsrc->offset / 8;\n+\t\treturn 0;\n+\t}\n \n-\tCHECK(!action, EINVAL);\n-\tCHECK(n_tokens == 3, EINVAL);\n+\t/* REGWR_RHI, REGWR_RMI. */\n+\tif (fidx && !fsrc) {\n+\t\tsrc_val = strtoull(src, &src, 0);\n+\t\tCHECK(!src[0], EINVAL);\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\t\tinstr->type = INSTR_REGWR_RMI;\n+\t\tif (idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGWR_RHI;\n \n-\ta = action_find(p, tokens[2]);\n-\tCHECK(a, EINVAL);\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc_val = src_val;\n+\t\treturn 0;\n+\t}\n \n-\tinstr->type = INSTR_JMP_ACTION_HIT;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\tinstr->jmp.action_id = a->id;\n-\treturn 0;\n-}\n+\t/* REGWR_RIH, REGWR_RIM. */\n+\tif (!fidx && fsrc) {\n+\t\tidx_val = strtoul(idx, &idx, 0);\n+\t\tCHECK(!idx[0], EINVAL);\n \n-static int\n-instr_jmp_action_miss_translate(struct rte_swx_pipeline *p,\n-\t\t\t\tstruct action *action,\n-\t\t\t\tchar **tokens,\n-\t\t\t\tint n_tokens,\n-\t\t\t\tstruct instruction *instr,\n-\t\t\t\tstruct instruction_data *data)\n-{\n-\tstruct action *a;\n+\t\tinstr->type = INSTR_REGWR_RIM;\n+\t\tif (idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGWR_RIH;\n \n-\tCHECK(!action, EINVAL);\n-\tCHECK(n_tokens == 3, EINVAL);\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx_val = idx_val;\n+\t\tinstr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;\n+\t\tinstr->regarray.dstsrc.n_bits = fsrc->n_bits;\n+\t\tinstr->regarray.dstsrc.offset = fsrc->offset / 8;\n+\t\treturn 0;\n+\t}\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\t/* REGWR_RII. */\n+\tsrc_val = strtoull(src, &src, 0);\n+\tCHECK(!src[0], EINVAL);\n \n-\ta = action_find(p, tokens[2]);\n-\tCHECK(a, EINVAL);\n+\tidx_val = strtoul(idx, &idx, 0);\n+\tCHECK(!idx[0], EINVAL);\n+\n+\tinstr->type = INSTR_REGWR_RII;\n+\tinstr->regarray.idx_val = idx_val;\n+\tinstr->regarray.dstsrc_val = src_val;\n \n-\tinstr->type = INSTR_JMP_ACTION_MISS;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\tinstr->jmp.action_id = a->id;\n \treturn 0;\n }\n \n static int\n-instr_jmp_eq_translate(struct rte_swx_pipeline *p,\n+instr_regadd_translate(struct rte_swx_pipeline *p,\n \t\t       struct action *action,\n \t\t       char **tokens,\n \t\t       int n_tokens,\n \t\t       struct instruction *instr,\n-\t\t       struct instruction_data *data)\n+\t\t       struct instruction_data *data __rte_unused)\n {\n-\tchar *a = tokens[2], *b = tokens[3];\n-\tstruct field *fa, *fb;\n-\tuint64_t b_val;\n-\tuint32_t a_struct_id, b_struct_id;\n+\tchar *regarray = tokens[1], *idx = tokens[2], *src = tokens[3];\n+\tstruct regarray *r;\n+\tstruct field *fidx, *fsrc;\n+\tuint64_t src_val;\n+\tuint32_t idx_struct_id, idx_val, src_struct_id;\n \n \tCHECK(n_tokens == 4, EINVAL);\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+\tr = regarray_find(p, regarray);\n+\tCHECK(r, EINVAL);\n \n-\tfa = struct_field_parse(p, action, a, &a_struct_id);\n-\tCHECK(fa, EINVAL);\n+\t/* REGADD_RHH, REGADD_RHM, REGADD_RMH, REGADD_RMM. */\n+\tfidx = struct_field_parse(p, action, idx, &idx_struct_id);\n+\tfsrc = struct_field_parse(p, action, src, &src_struct_id);\n+\tif (fidx && fsrc) {\n+\t\tinstr->type = INSTR_REGADD_RMM;\n+\t\tif (idx[0] == 'h' && src[0] == 'm')\n+\t\t\tinstr->type = INSTR_REGADD_RHM;\n+\t\tif (idx[0] == 'm' && src[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGADD_RMH;\n+\t\tif (idx[0] == 'h' && src[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGADD_RHH;\n+\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;\n+\t\tinstr->regarray.dstsrc.n_bits = fsrc->n_bits;\n+\t\tinstr->regarray.dstsrc.offset = fsrc->offset / 8;\n+\t\treturn 0;\n+\t}\n \n-\t/* JMP_EQ or JMP_EQ_S. */\n-\tfb = struct_field_parse(p, action, b, &b_struct_id);\n-\tif (fb) {\n-\t\tinstr->type = INSTR_JMP_EQ;\n-\t\tif ((a[0] == 'h' && b[0] != 'h') ||\n-\t\t    (a[0] != 'h' && b[0] == 'h'))\n-\t\t\tinstr->type = INSTR_JMP_EQ_S;\n-\t\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\t/* REGADD_RHI, REGADD_RMI. */\n+\tif (fidx && !fsrc) {\n+\t\tsrc_val = strtoull(src, &src, 0);\n+\t\tCHECK(!src[0], EINVAL);\n \n-\t\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n-\t\tinstr->jmp.a.n_bits = fa->n_bits;\n-\t\tinstr->jmp.a.offset = fa->offset / 8;\n-\t\tinstr->jmp.b.struct_id = (uint8_t)b_struct_id;\n-\t\tinstr->jmp.b.n_bits = fb->n_bits;\n-\t\tinstr->jmp.b.offset = fb->offset / 8;\n+\t\tinstr->type = INSTR_REGADD_RMI;\n+\t\tif (idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGADD_RHI;\n+\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx.struct_id = (uint8_t)idx_struct_id;\n+\t\tinstr->regarray.idx.n_bits = fidx->n_bits;\n+\t\tinstr->regarray.idx.offset = fidx->offset / 8;\n+\t\tinstr->regarray.dstsrc_val = src_val;\n \t\treturn 0;\n \t}\n \n-\t/* JMP_EQ_I. */\n-\tb_val = strtoull(b, &b, 0);\n-\tCHECK(!b[0], EINVAL);\n+\t/* REGADD_RIH, REGADD_RIM. */\n+\tif (!fidx && fsrc) {\n+\t\tidx_val = strtoul(idx, &idx, 0);\n+\t\tCHECK(!idx[0], EINVAL);\n \n-\tif (a[0] == 'h')\n-\t\tb_val = hton64(b_val) >> (64 - fa->n_bits);\n+\t\tinstr->type = INSTR_REGADD_RIM;\n+\t\tif (idx[0] == 'h')\n+\t\t\tinstr->type = INSTR_REGADD_RIH;\n \n-\tinstr->type = INSTR_JMP_EQ_I;\n-\tinstr->jmp.ip = NULL; /* Resolved later. */\n-\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n-\tinstr->jmp.a.n_bits = fa->n_bits;\n-\tinstr->jmp.a.offset = fa->offset / 8;\n-\tinstr->jmp.b_val = b_val;\n+\t\tinstr->regarray.regarray_id = r->id;\n+\t\tinstr->regarray.idx_val = idx_val;\n+\t\tinstr->regarray.dstsrc.struct_id = (uint8_t)src_struct_id;\n+\t\tinstr->regarray.dstsrc.n_bits = fsrc->n_bits;\n+\t\tinstr->regarray.dstsrc.offset = fsrc->offset / 8;\n+\t\treturn 0;\n+\t}\n+\n+\t/* REGADD_RII. */\n+\tsrc_val = strtoull(src, &src, 0);\n+\tCHECK(!src[0], EINVAL);\n+\n+\tidx_val = strtoul(idx, &idx, 0);\n+\tCHECK(!idx[0], EINVAL);\n+\n+\tinstr->type = INSTR_REGADD_RII;\n+\tinstr->regarray.idx_val = idx_val;\n+\tinstr->regarray.dstsrc_val = src_val;\n \treturn 0;\n }\n \n-static int\n-instr_jmp_neq_translate(struct rte_swx_pipeline *p,\n-\t\t\tstruct action *action,\n-\t\t\tchar **tokens,\n-\t\t\tint n_tokens,\n-\t\t\tstruct instruction *instr,\n-\t\t\tstruct instruction_data *data)\n-{\n-\tchar *a = tokens[2], *b = tokens[3];\n-\tstruct field *fa, *fb;\n-\tuint64_t b_val;\n-\tuint32_t a_struct_id, b_struct_id;\n+#define REGPREFETCH_RM(pipeline, thread, ip)                                                    \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx64_mask = UINT64_MAX >> (64 - (ip)->regarray.idx.n_bits);                   \\\n+\tuint64_t idx = idx64 & idx64_mask & r->size_mask;                                       \\\n+\t                                                                                        \\\n+\trte_prefetch0(&regarray[idx]);                                                          \\\n+}\n \n-\tCHECK(n_tokens == 4, EINVAL);\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n \n-\tstrcpy(data->jmp_label, tokens[1]);\n+#define REGPREFETCH_RH(pipeline, thread, ip)                                                    \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx = (ntoh64(idx64) >> (64 - (ip)->regarray.idx.n_bits)) & r->size_mask;      \\\n+\t                                                                                        \\\n+\trte_prefetch0(&regarray[idx]);                                                          \\\n+}\n \n-\tfa = struct_field_parse(p, action, a, &a_struct_id);\n-\tCHECK(fa, EINVAL);\n+#else\n \n-\t/* JMP_NEQ or JMP_NEQ_S. */\n-\tfb = struct_field_parse(p, action, b, &b_struct_id);\n-\tif (fb) {\n-\t\tinstr->type = INSTR_JMP_NEQ;\n-\t\tif ((a[0] == 'h' && b[0] != 'h') ||\n-\t\t    (a[0] != 'h' && b[0] == 'h'))\n-\t\t\tinstr->type = INSTR_JMP_NEQ_S;\n-\t\tinstr->jmp.ip = NULL; /* Resolved later. */\n+#define REGPREFETCH_RH REGPREFETCH_RM\n \n-\t\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n-\t\tinstr->jmp.a.n_bits = fa->n_bits;\n-\t\tinstr->jmp.a.offset = fa->offset / 8;\n-\t\tinstr->jmp.b.struct_id = (uint8_t)b_struct_id;\n-\t\tinstr->jmp.b.n_bits = fb->n_bits;\n-\t\tinstr->jmp.b.offset = fb->offset / 8;\n-\t\treturn 0;\n-\t}\n+#endif\n \n-\t/* JMP_NEQ_I. */\n-\tb_val = strtoull(b, &b, 0);\n+#define REGPREFETCH_RI(pipeline, thread, ip)                                                    \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint64_t idx = (ip)->regarray.idx_val & r->size_mask;                                   \\\n+\t                                                                                        \\\n+\trte_prefetch0(&regarray[idx]);                                                          \\\n+}\n+\n+static inline void\n+instr_regprefetch_rh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regprefetch (r[h])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGPREFETCH_RH(p, t, ip);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regprefetch_rm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regprefetch (r[m])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGPREFETCH_RM(p, t, ip);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regprefetch_ri_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regprefetch (r[i])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGPREFETCH_RI(p, t, ip);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+#define REGRD_MRM(pipeline, thread, ip)                                                         \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx64_mask = UINT64_MAX >> (64 - (ip)->regarray.idx.n_bits);                   \\\n+\tuint64_t idx = idx64 & idx64_mask & r->size_mask;                                       \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc64_mask = UINT64_MAX >> (64 - (ip)->regarray.dstsrc.n_bits);             \\\n+\t                                                                                        \\\n+\t*dstsrc64_ptr = (dstsrc64 & ~dstsrc64_mask) | (regarray[idx] & dstsrc64_mask);          \\\n+}\n+\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n+\n+#define REGRD_MRH(pipeline, thread, ip)                                                         \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx = (ntoh64(idx64) >> (64 - (ip)->regarray.idx.n_bits)) & r->size_mask;      \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc64_mask = UINT64_MAX >> (64 - (ip)->regarray.dstsrc.n_bits);             \\\n+\t                                                                                        \\\n+\t*dstsrc64_ptr = (dstsrc64 & ~dstsrc64_mask) | (regarray[idx] & dstsrc64_mask);          \\\n+}\n+\n+#define REGRD_HRM(pipeline, thread, ip)                                                         \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx64_mask = UINT64_MAX >> (64 - (ip)->regarray.idx.n_bits);                   \\\n+\tuint64_t idx = idx64 & idx64_mask & r->size_mask;                                       \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc64_mask = UINT64_MAX >> (64 - (ip)->regarray.dstsrc.n_bits);             \\\n+\t                                                                                        \\\n+\t*dstsrc64_ptr = (dstsrc64 & ~dstsrc64_mask) | (hton64(regarray[idx]) & dstsrc64_mask);  \\\n+}\n+\n+#define REGRD_HRH(pipeline, thread, ip)                                                         \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx = (ntoh64(idx64) >> (64 - (ip)->regarray.idx.n_bits)) & r->size_mask;      \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc64_mask = UINT64_MAX >> (64 - (ip)->regarray.dstsrc.n_bits);             \\\n+\t                                                                                        \\\n+\t*dstsrc64_ptr = (dstsrc64 & ~dstsrc64_mask) | (hton64(regarray[idx]) & dstsrc64_mask);  \\\n+}\n+\n+#else\n+\n+#define REGRD_MRH REGRD_MRM\n+#define REGRD_HRM REGRD_MRM\n+#define REGRD_HRH REGRD_MRM\n+\n+#endif\n+\n+#define REGRD_MRI(pipeline, thread, ip)                                                         \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint64_t idx = (ip)->regarray.idx_val & r->size_mask;                                   \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc64_mask = UINT64_MAX >> (64 - (ip)->regarray.dstsrc.n_bits);             \\\n+\t                                                                                        \\\n+\t*dstsrc64_ptr = (dstsrc64 & ~dstsrc64_mask) | (regarray[idx] & dstsrc64_mask);          \\\n+}\n+\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n+\n+#define REGRD_HRI(pipeline, thread, ip)                                                         \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint64_t idx = (ip)->regarray.idx_val & r->size_mask;                                   \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc64_mask = UINT64_MAX >> (64 - (ip)->regarray.dstsrc.n_bits);             \\\n+\t                                                                                        \\\n+\t*dstsrc64_ptr = (dstsrc64 & ~dstsrc64_mask) | (hton64(regarray[idx]) & dstsrc64_mask);  \\\n+}\n+\n+#else\n+\n+#define REGRD_HRI REGRD_MRI\n+\n+#endif\n+\n+static inline void\n+instr_regrd_hrh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regrd (h = r[h])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGRD_HRH(p, t, ip);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_hrm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regrd (h = r[m])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGRD_HRM(p, t, ip);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_mrh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regrd (m = r[h])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGRD_MRH(p, t, ip);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_mrm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regrd (m = r[m])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGRD_MRM(p, t, ip);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_hri_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regrd (h = r[i])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGRD_HRI(p, t, ip);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regrd_mri_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regrd (m = r[i])\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGRD_MRI(p, t, ip);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+#define REGWR_RMM(pipeline, thread, ip, operator)                                               \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx64_mask = UINT64_MAX >> (64 - (ip)->regarray.idx.n_bits);                   \\\n+\tuint64_t idx = idx64 & idx64_mask & r->size_mask;                                       \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc64_mask = UINT64_MAX >> (64 - (ip)->regarray.dstsrc.n_bits);             \\\n+\tuint64_t dstsrc = dstsrc64 & dstsrc64_mask;                                             \\\n+\t                                                                                        \\\n+\tregarray[idx] operator dstsrc;                                                          \\\n+}\n+\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n+\n+#define REGWR_RMH(pipeline, thread, ip, operator)                                               \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx64_mask = UINT64_MAX >> (64 - (ip)->regarray.idx.n_bits);                   \\\n+\tuint64_t idx = idx64 & idx64_mask & r->size_mask;                                       \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc = ntoh64(dstsrc64) >> (64 - (ip)->regarray.dstsrc.n_bits);              \\\n+\t                                                                                        \\\n+\tregarray[idx] operator dstsrc;                                                          \\\n+}\n+\n+#define REGWR_RHM(pipeline, thread, ip, operator)                                               \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx = (ntoh64(idx64) >> (64 - (ip)->regarray.idx.n_bits)) & r->size_mask;      \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc64_mask = UINT64_MAX >> (64 - (ip)->regarray.dstsrc.n_bits);             \\\n+\tuint64_t dstsrc = dstsrc64 & dstsrc64_mask;                                             \\\n+\t                                                                                        \\\n+\tregarray[idx] operator dstsrc;                                                          \\\n+}\n+\n+#define REGWR_RHH(pipeline, thread, ip, operator)                                               \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx = (ntoh64(idx64) >> (64 - (ip)->regarray.idx.n_bits)) & r->size_mask;      \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc = ntoh64(dstsrc64) >> (64 - (ip)->regarray.dstsrc.n_bits);              \\\n+\t                                                                                        \\\n+\tregarray[idx] operator dstsrc;                                                          \\\n+}\n+\n+#else\n+\n+#define REGWR_RMH REGWR_RMM\n+#define REGWR_RHM REGWR_RMM\n+#define REGWR_RHH REGWR_RMM\n+\n+#endif\n+\n+#define REGWR_RMI(pipeline, thread, ip, operator)                                               \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx64_mask = UINT64_MAX >> (64 - (ip)->regarray.idx.n_bits);                   \\\n+\tuint64_t idx = idx64 & idx64_mask & r->size_mask;                                       \\\n+\t                                                                                        \\\n+\tuint64_t dstsrc = (ip)->regarray.dstsrc_val;                                            \\\n+\t                                                                                        \\\n+\tregarray[idx] operator dstsrc;                                                          \\\n+}\n+\n+#define REGWR_RIM(pipeline, thread, ip, operator)                                               \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint64_t idx = (ip)->regarray.idx_val & r->size_mask;                                   \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc64_mask = UINT64_MAX >> (64 - (ip)->regarray.dstsrc.n_bits);             \\\n+\tuint64_t dstsrc = dstsrc64 & dstsrc64_mask;                                             \\\n+\t                                                                                        \\\n+\tregarray[idx] operator dstsrc;                                                          \\\n+}\n+\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n+\n+#define REGWR_RHI(pipeline, thread, ip, operator)                                               \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint8_t *idx_struct = (thread)->structs[(ip)->regarray.idx.struct_id];                  \\\n+\tuint64_t *idx64_ptr = (uint64_t *)&idx_struct[(ip)->regarray.idx.offset];               \\\n+\tuint64_t idx64 = *idx64_ptr;                                                            \\\n+\tuint64_t idx = (ntoh64(idx64) >> (64 - (ip)->regarray.idx.n_bits)) & r->size_mask;      \\\n+\t                                                                                        \\\n+\tuint64_t dstsrc = (ip)->regarray.dstsrc_val;                                            \\\n+\t                                                                                        \\\n+\tregarray[idx] operator dstsrc;                                                          \\\n+}\n+\n+#define REGWR_RIH(pipeline, thread, ip, operator)                                               \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint64_t idx = (ip)->regarray.idx_val & r->size_mask;                                   \\\n+\t                                                                                        \\\n+\tuint8_t *dstsrc_struct = (thread)->structs[(ip)->regarray.dstsrc.struct_id];            \\\n+\tuint64_t *dstsrc64_ptr = (uint64_t *)&dstsrc_struct[(ip)->regarray.dstsrc.offset];      \\\n+\tuint64_t dstsrc64 = *dstsrc64_ptr;                                                      \\\n+\tuint64_t dstsrc = ntoh64(dstsrc64) >> (64 - (ip)->regarray.dstsrc.n_bits);              \\\n+\t                                                                                        \\\n+\tregarray[idx] operator dstsrc;                                                          \\\n+}\n+\n+#else\n+\n+#define REGWR_RHI REGWR_RMI\n+#define REGWR_RIH REGWR_RIM\n+\n+#endif\n+\n+#define REGWR_RII(pipeline, thread, ip, operator)                                               \\\n+{                                                                                               \\\n+\tstruct regarray_runtime *r = &(pipeline)->regarray_runtime[(ip)->regarray.regarray_id]; \\\n+\tuint64_t *regarray = r->regarray;                                                       \\\n+\t                                                                                        \\\n+\tuint64_t idx = (ip)->regarray.idx_val & r->size_mask;                                   \\\n+\t                                                                                        \\\n+\tuint64_t dstsrc = (ip)->regarray.dstsrc_val;                                            \\\n+\t                                                                                        \\\n+\tregarray[idx] operator dstsrc;                                                          \\\n+}\n+\n+static inline void\n+instr_regwr_rhh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[h] = h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RHH(p, t, ip, =);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rhm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[h] = m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RHM(p, t, ip, =);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rmh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[m] = h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RMH(p, t, ip, =);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rmm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[m] = m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RMM(p, t, ip, =);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rhi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[h] = i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RHI(p, t, ip, =);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rmi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[m] = i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RMI(p, t, ip, =);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rih_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[i] = h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RIH(p, t, ip, =);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rim_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[i] = m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RIM(p, t, ip, =);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regwr_rii_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regwr (r[i] = i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RII(p, t, ip, =);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rhh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[h] += h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RHH(p, t, ip, +=);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rhm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[h] += m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RHM(p, t, ip, +=);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rmh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[m] += h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RMH(p, t, ip, +=);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rmm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[m] += m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RMM(p, t, ip, +=);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rhi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[h] += i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RHI(p, t, ip, +=);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rmi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[m] += i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RMI(p, t, ip, +=);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rih_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[i] += h)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RIH(p, t, ip, +=);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rim_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[i] += m)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RIM(p, t, ip, +=);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+static inline void\n+instr_regadd_rii_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] regadd (r[i] += i)\\n\", p->thread_id);\n+\n+\t/* Structs. */\n+\tREGWR_RII(p, t, ip, +=);\n+\n+\t/* Thread. */\n+\tthread_ip_inc(p);\n+}\n+\n+/*\n+ * jmp.\n+ */\n+static struct action *\n+action_find(struct rte_swx_pipeline *p, const char *name);\n+\n+static int\n+instr_jmp_translate(struct rte_swx_pipeline *p __rte_unused,\n+\t\t    struct action *action __rte_unused,\n+\t\t    char **tokens,\n+\t\t    int n_tokens,\n+\t\t    struct instruction *instr,\n+\t\t    struct instruction_data *data)\n+{\n+\tCHECK(n_tokens == 2, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tinstr->type = INSTR_JMP;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_valid_translate(struct rte_swx_pipeline *p,\n+\t\t\t  struct action *action __rte_unused,\n+\t\t\t  char **tokens,\n+\t\t\t  int n_tokens,\n+\t\t\t  struct instruction *instr,\n+\t\t\t  struct instruction_data *data)\n+{\n+\tstruct header *h;\n+\n+\tCHECK(n_tokens == 3, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\th = header_parse(p, tokens[2]);\n+\tCHECK(h, EINVAL);\n+\n+\tinstr->type = INSTR_JMP_VALID;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.header_id = h->id;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_invalid_translate(struct rte_swx_pipeline *p,\n+\t\t\t    struct action *action __rte_unused,\n+\t\t\t    char **tokens,\n+\t\t\t    int n_tokens,\n+\t\t\t    struct instruction *instr,\n+\t\t\t    struct instruction_data *data)\n+{\n+\tstruct header *h;\n+\n+\tCHECK(n_tokens == 3, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\th = header_parse(p, tokens[2]);\n+\tCHECK(h, EINVAL);\n+\n+\tinstr->type = INSTR_JMP_INVALID;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.header_id = h->id;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_hit_translate(struct rte_swx_pipeline *p __rte_unused,\n+\t\t\tstruct action *action,\n+\t\t\tchar **tokens,\n+\t\t\tint n_tokens,\n+\t\t\tstruct instruction *instr,\n+\t\t\tstruct instruction_data *data)\n+{\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 2, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tinstr->type = INSTR_JMP_HIT;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_miss_translate(struct rte_swx_pipeline *p __rte_unused,\n+\t\t\t struct action *action,\n+\t\t\t char **tokens,\n+\t\t\t int n_tokens,\n+\t\t\t struct instruction *instr,\n+\t\t\t struct instruction_data *data)\n+{\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 2, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tinstr->type = INSTR_JMP_MISS;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_action_hit_translate(struct rte_swx_pipeline *p,\n+\t\t\t       struct action *action,\n+\t\t\t       char **tokens,\n+\t\t\t       int n_tokens,\n+\t\t\t       struct instruction *instr,\n+\t\t\t       struct instruction_data *data)\n+{\n+\tstruct action *a;\n+\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 3, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\ta = action_find(p, tokens[2]);\n+\tCHECK(a, EINVAL);\n+\n+\tinstr->type = INSTR_JMP_ACTION_HIT;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.action_id = a->id;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_action_miss_translate(struct rte_swx_pipeline *p,\n+\t\t\t\tstruct action *action,\n+\t\t\t\tchar **tokens,\n+\t\t\t\tint n_tokens,\n+\t\t\t\tstruct instruction *instr,\n+\t\t\t\tstruct instruction_data *data)\n+{\n+\tstruct action *a;\n+\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 3, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\ta = action_find(p, tokens[2]);\n+\tCHECK(a, EINVAL);\n+\n+\tinstr->type = INSTR_JMP_ACTION_MISS;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.action_id = a->id;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_eq_translate(struct rte_swx_pipeline *p,\n+\t\t       struct action *action,\n+\t\t       char **tokens,\n+\t\t       int n_tokens,\n+\t\t       struct instruction *instr,\n+\t\t       struct instruction_data *data)\n+{\n+\tchar *a = tokens[2], *b = tokens[3];\n+\tstruct field *fa, *fb;\n+\tuint64_t b_val;\n+\tuint32_t a_struct_id, b_struct_id;\n+\n+\tCHECK(n_tokens == 4, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tfa = struct_field_parse(p, action, a, &a_struct_id);\n+\tCHECK(fa, EINVAL);\n+\n+\t/* JMP_EQ or JMP_EQ_S. */\n+\tfb = struct_field_parse(p, action, b, &b_struct_id);\n+\tif (fb) {\n+\t\tinstr->type = INSTR_JMP_EQ;\n+\t\tif ((a[0] == 'h' && b[0] != 'h') ||\n+\t\t    (a[0] != 'h' && b[0] == 'h'))\n+\t\t\tinstr->type = INSTR_JMP_EQ_S;\n+\t\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\n+\t\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\t\tinstr->jmp.a.n_bits = fa->n_bits;\n+\t\tinstr->jmp.a.offset = fa->offset / 8;\n+\t\tinstr->jmp.b.struct_id = (uint8_t)b_struct_id;\n+\t\tinstr->jmp.b.n_bits = fb->n_bits;\n+\t\tinstr->jmp.b.offset = fb->offset / 8;\n+\t\treturn 0;\n+\t}\n+\n+\t/* JMP_EQ_I. */\n+\tb_val = strtoull(b, &b, 0);\n+\tCHECK(!b[0], EINVAL);\n+\n+\tif (a[0] == 'h')\n+\t\tb_val = hton64(b_val) >> (64 - fa->n_bits);\n+\n+\tinstr->type = INSTR_JMP_EQ_I;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\tinstr->jmp.a.n_bits = fa->n_bits;\n+\tinstr->jmp.a.offset = fa->offset / 8;\n+\tinstr->jmp.b_val = b_val;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_neq_translate(struct rte_swx_pipeline *p,\n+\t\t\tstruct action *action,\n+\t\t\tchar **tokens,\n+\t\t\tint n_tokens,\n+\t\t\tstruct instruction *instr,\n+\t\t\tstruct instruction_data *data)\n+{\n+\tchar *a = tokens[2], *b = tokens[3];\n+\tstruct field *fa, *fb;\n+\tuint64_t b_val;\n+\tuint32_t a_struct_id, b_struct_id;\n+\n+\tCHECK(n_tokens == 4, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tfa = struct_field_parse(p, action, a, &a_struct_id);\n+\tCHECK(fa, EINVAL);\n+\n+\t/* JMP_NEQ or JMP_NEQ_S. */\n+\tfb = struct_field_parse(p, action, b, &b_struct_id);\n+\tif (fb) {\n+\t\tinstr->type = INSTR_JMP_NEQ;\n+\t\tif ((a[0] == 'h' && b[0] != 'h') ||\n+\t\t    (a[0] != 'h' && b[0] == 'h'))\n+\t\t\tinstr->type = INSTR_JMP_NEQ_S;\n+\t\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\n+\t\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\t\tinstr->jmp.a.n_bits = fa->n_bits;\n+\t\tinstr->jmp.a.offset = fa->offset / 8;\n+\t\tinstr->jmp.b.struct_id = (uint8_t)b_struct_id;\n+\t\tinstr->jmp.b.n_bits = fb->n_bits;\n+\t\tinstr->jmp.b.offset = fb->offset / 8;\n+\t\treturn 0;\n+\t}\n+\n+\t/* JMP_NEQ_I. */\n+\tb_val = strtoull(b, &b, 0);\n \tCHECK(!b[0], EINVAL);\n \n \tif (a[0] == 'h')\n@@ -5475,6 +6584,38 @@ instr_translate(struct rte_swx_pipeline *p,\n \t\t\t\t\t       instr,\n \t\t\t\t\t       data);\n \n+\tif (!strcmp(tokens[tpos], \"regprefetch\"))\n+\t\treturn instr_regprefetch_translate(p,\n+\t\t\t\t\t\t   action,\n+\t\t\t\t\t\t   &tokens[tpos],\n+\t\t\t\t\t\t   n_tokens - tpos,\n+\t\t\t\t\t\t   instr,\n+\t\t\t\t\t\t   data);\n+\n+\tif (!strcmp(tokens[tpos], \"regrd\"))\n+\t\treturn instr_regrd_translate(p,\n+\t\t\t\t\t     action,\n+\t\t\t\t\t     &tokens[tpos],\n+\t\t\t\t\t     n_tokens - tpos,\n+\t\t\t\t\t     instr,\n+\t\t\t\t\t     data);\n+\n+\tif (!strcmp(tokens[tpos], \"regwr\"))\n+\t\treturn instr_regwr_translate(p,\n+\t\t\t\t\t     action,\n+\t\t\t\t\t     &tokens[tpos],\n+\t\t\t\t\t     n_tokens - tpos,\n+\t\t\t\t\t     instr,\n+\t\t\t\t\t     data);\n+\n+\tif (!strcmp(tokens[tpos], \"regadd\"))\n+\t\treturn instr_regadd_translate(p,\n+\t\t\t\t\t      action,\n+\t\t\t\t\t      &tokens[tpos],\n+\t\t\t\t\t      n_tokens - tpos,\n+\t\t\t\t\t      instr,\n+\t\t\t\t\t      data);\n+\n \tif (!strcmp(tokens[tpos], \"table\"))\n \t\treturn instr_table_translate(p,\n \t\t\t\t\t     action,\n@@ -6111,6 +7252,37 @@ static instr_exec_t instruction_table[] = {\n \t[INSTR_ALU_SHR_MI] = instr_alu_shr_mi_exec,\n \t[INSTR_ALU_SHR_HI] = instr_alu_shr_hi_exec,\n \n+\t[INSTR_REGPREFETCH_RH] = instr_regprefetch_rh_exec,\n+\t[INSTR_REGPREFETCH_RM] = instr_regprefetch_rm_exec,\n+\t[INSTR_REGPREFETCH_RI] = instr_regprefetch_ri_exec,\n+\n+\t[INSTR_REGRD_HRH] = instr_regrd_hrh_exec,\n+\t[INSTR_REGRD_HRM] = instr_regrd_hrm_exec,\n+\t[INSTR_REGRD_MRH] = instr_regrd_mrh_exec,\n+\t[INSTR_REGRD_MRM] = instr_regrd_mrm_exec,\n+\t[INSTR_REGRD_HRI] = instr_regrd_hri_exec,\n+\t[INSTR_REGRD_MRI] = instr_regrd_mri_exec,\n+\n+\t[INSTR_REGWR_RHH] = instr_regwr_rhh_exec,\n+\t[INSTR_REGWR_RHM] = instr_regwr_rhm_exec,\n+\t[INSTR_REGWR_RMH] = instr_regwr_rmh_exec,\n+\t[INSTR_REGWR_RMM] = instr_regwr_rmm_exec,\n+\t[INSTR_REGWR_RHI] = instr_regwr_rhi_exec,\n+\t[INSTR_REGWR_RMI] = instr_regwr_rmi_exec,\n+\t[INSTR_REGWR_RIH] = instr_regwr_rih_exec,\n+\t[INSTR_REGWR_RIM] = instr_regwr_rim_exec,\n+\t[INSTR_REGWR_RII] = instr_regwr_rii_exec,\n+\n+\t[INSTR_REGADD_RHH] = instr_regadd_rhh_exec,\n+\t[INSTR_REGADD_RHM] = instr_regadd_rhm_exec,\n+\t[INSTR_REGADD_RMH] = instr_regadd_rmh_exec,\n+\t[INSTR_REGADD_RMM] = instr_regadd_rmm_exec,\n+\t[INSTR_REGADD_RHI] = instr_regadd_rhi_exec,\n+\t[INSTR_REGADD_RMI] = instr_regadd_rmi_exec,\n+\t[INSTR_REGADD_RIH] = instr_regadd_rih_exec,\n+\t[INSTR_REGADD_RIM] = instr_regadd_rim_exec,\n+\t[INSTR_REGADD_RII] = instr_regadd_rii_exec,\n+\n \t[INSTR_TABLE] = instr_table_exec,\n \t[INSTR_EXTERN_OBJ] = instr_extern_obj_exec,\n \t[INSTR_EXTERN_FUNC] = instr_extern_func_exec,\n@@ -6823,6 +7995,119 @@ table_free(struct rte_swx_pipeline *p)\n \t}\n }\n \n+/*\n+ * Register array.\n+ */\n+static struct regarray *\n+regarray_find(struct rte_swx_pipeline *p, const char *name)\n+{\n+\tstruct regarray *elem;\n+\n+\tTAILQ_FOREACH(elem, &p->regarrays, node)\n+\t\tif (!strcmp(elem->name, name))\n+\t\t\treturn elem;\n+\n+\treturn NULL;\n+}\n+\n+static struct regarray *\n+regarray_find_by_id(struct rte_swx_pipeline *p, uint32_t id)\n+{\n+\tstruct regarray *elem = NULL;\n+\n+\tTAILQ_FOREACH(elem, &p->regarrays, node)\n+\t\tif (elem->id == id)\n+\t\t\treturn elem;\n+\n+\treturn NULL;\n+}\n+\n+int\n+rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p,\n+\t\t\t      const char *name,\n+\t\t\t      uint32_t size)\n+{\n+\tstruct regarray *r;\n+\n+\tCHECK(p, EINVAL);\n+\n+\tCHECK_NAME(name, EINVAL);\n+\tCHECK(!regarray_find(p, name), EEXIST);\n+\n+\tCHECK(size, EINVAL);\n+\tsize = rte_align32pow2(size);\n+\n+\t/* Memory allocation. */\n+\tr = calloc(1, sizeof(struct regarray));\n+\tCHECK(r, ENOMEM);\n+\n+\t/* Node initialization. */\n+\tstrcpy(r->name, name);\n+\tr->size = size;\n+\tr->id = p->n_regarrays;\n+\n+\t/* Node add to tailq. */\n+\tTAILQ_INSERT_TAIL(&p->regarrays, r, node);\n+\tp->n_regarrays++;\n+\n+\treturn 0;\n+}\n+\n+static int\n+regarray_build(struct rte_swx_pipeline *p)\n+{\n+\tstruct regarray *regarray;\n+\n+\tp->regarray_runtime = calloc(p->n_regarrays, sizeof(struct regarray_runtime));\n+\tCHECK(p->regarray_runtime, ENOMEM);\n+\n+\tTAILQ_FOREACH(regarray, &p->regarrays, node) {\n+\t\tstruct regarray_runtime *r = &p->regarray_runtime[regarray->id];\n+\n+\t\tr->regarray = calloc(regarray->size, sizeof(uint64_t));\n+\t\tCHECK(r->regarray, ENOMEM);\n+\n+\t\tr->size_mask = regarray->size - 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+regarray_build_free(struct rte_swx_pipeline *p)\n+{\n+\tuint32_t i;\n+\n+\tif (!p->regarray_runtime)\n+\t\treturn;\n+\n+\tfor (i = 0; i < p->n_regarrays; i++) {\n+\t\tstruct regarray_runtime *r = &p->regarray_runtime[i];\n+\n+\t\tfree(r->regarray);\n+\t}\n+\n+\tfree(p->regarray_runtime);\n+\tp->regarray_runtime = NULL;\n+}\n+\n+static void\n+regarray_free(struct rte_swx_pipeline *p)\n+{\n+\tregarray_build_free(p);\n+\n+\tfor ( ; ; ) {\n+\t\tstruct regarray *elem;\n+\n+\t\telem = TAILQ_FIRST(&p->regarrays);\n+\t\tif (!elem)\n+\t\t\tbreak;\n+\n+\t\tTAILQ_REMOVE(&p->regarrays, elem, node);\n+\t\tfree(elem);\n+\t}\n+}\n+\n /*\n  * Pipeline.\n  */\n@@ -6851,6 +8136,7 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)\n \tTAILQ_INIT(&pipeline->actions);\n \tTAILQ_INIT(&pipeline->table_types);\n \tTAILQ_INIT(&pipeline->tables);\n+\tTAILQ_INIT(&pipeline->regarrays);\n \n \tpipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */\n \tpipeline->numa_node = numa_node;\n@@ -6867,6 +8153,7 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p)\n \n \tfree(p->instructions);\n \n+\tregarray_free(p);\n \ttable_state_free(p);\n \ttable_free(p);\n \taction_free(p);\n@@ -6951,10 +8238,15 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p)\n \tif (status)\n \t\tgoto error;\n \n+\tstatus = regarray_build(p);\n+\tif (status)\n+\t\tgoto error;\n+\n \tp->build_done = 1;\n \treturn 0;\n \n error:\n+\tregarray_build_free(p);\n \ttable_state_build_free(p);\n \ttable_build_free(p);\n \taction_build_free(p);\n@@ -7015,6 +8307,7 @@ rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p,\n \tpipeline->n_ports_out = p->n_ports_out;\n \tpipeline->n_actions = n_actions;\n \tpipeline->n_tables = n_tables;\n+\tpipeline->n_regarrays = p->n_regarrays;\n \n \treturn 0;\n }\n@@ -7222,3 +8515,64 @@ rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p,\n \tport->type->ops.stats_read(port->obj, stats);\n \treturn 0;\n }\n+\n+int\n+rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p,\n+\t\t\t      uint32_t regarray_id,\n+\t\t\t      struct rte_swx_ctl_regarray_info *regarray)\n+{\n+\tstruct regarray *r;\n+\n+\tif (!p || !regarray)\n+\t\treturn -EINVAL;\n+\n+\tr = regarray_find_by_id(p, regarray_id);\n+\tif (!r)\n+\t\treturn -EINVAL;\n+\n+\tstrcpy(regarray->name, r->name);\n+\tregarray->size = r->size;\n+\treturn 0;\n+}\n+\n+int\n+rte_swx_ctl_pipeline_regarray_read(struct rte_swx_pipeline *p,\n+\t\t\t\t   const char *regarray_name,\n+\t\t\t\t   uint32_t regarray_index,\n+\t\t\t\t   uint64_t *value)\n+{\n+\tstruct regarray *regarray;\n+\tstruct regarray_runtime *r;\n+\n+\tif (!p || !regarray_name || !value)\n+\t\treturn -EINVAL;\n+\n+\tregarray = regarray_find(p, regarray_name);\n+\tif (!regarray || (regarray_index >= regarray->size))\n+\t\treturn -EINVAL;\n+\n+\tr = &p->regarray_runtime[regarray->id];\n+\t*value = r->regarray[regarray_index];\n+\treturn 0;\n+}\n+\n+int\n+rte_swx_ctl_pipeline_regarray_write(struct rte_swx_pipeline *p,\n+\t\t\t\t   const char *regarray_name,\n+\t\t\t\t   uint32_t regarray_index,\n+\t\t\t\t   uint64_t value)\n+{\n+\tstruct regarray *regarray;\n+\tstruct regarray_runtime *r;\n+\n+\tif (!p || !regarray_name)\n+\t\treturn -EINVAL;\n+\n+\tregarray = regarray_find(p, regarray_name);\n+\tif (!regarray || (regarray_index >= regarray->size))\n+\t\treturn -EINVAL;\n+\n+\tr = &p->regarray_runtime[regarray->id];\n+\tr->regarray[regarray_index] = value;\n+\treturn 0;\n+}\ndiff --git a/lib/librte_pipeline/rte_swx_pipeline.h b/lib/librte_pipeline/rte_swx_pipeline.h\nindex f0a2cef77..c6e4e50a8 100644\n--- a/lib/librte_pipeline/rte_swx_pipeline.h\n+++ b/lib/librte_pipeline/rte_swx_pipeline.h\n@@ -616,6 +616,27 @@ rte_swx_pipeline_table_config(struct rte_swx_pipeline *p,\n \t\t\t      const char *args,\n \t\t\t      uint32_t size);\n \n+/**\n+ * Pipeline register array configure\n+ *\n+ * @param[in] p\n+ *   Pipeline handle.\n+ * @param[in] name\n+ *   Register array name.\n+ * @param[in] size\n+ *   Number of registers in the array. Each register is 64-bit in size.\n+ * @return\n+ *   0 on success or the following error codes otherwise:\n+ *   -EINVAL: Invalid argument;\n+ *   -ENOMEM: Not enough space/cannot allocate memory;\n+ *   -EEXIST: Register array with this name already exists.\n+ */\n+__rte_experimental\n+int\n+rte_swx_pipeline_regarray_config(struct rte_swx_pipeline *p,\n+\t\t\t\t const char *name,\n+\t\t\t\t uint32_t size);\n+\n /**\n  * Pipeline instructions configure\n  *\ndiff --git a/lib/librte_pipeline/rte_swx_pipeline_spec.c b/lib/librte_pipeline/rte_swx_pipeline_spec.c\nindex f7884491b..31dcfc4c3 100644\n--- a/lib/librte_pipeline/rte_swx_pipeline_spec.c\n+++ b/lib/librte_pipeline/rte_swx_pipeline_spec.c\n@@ -940,6 +940,68 @@ table_block_parse(struct table_spec *s,\n \treturn -EINVAL;\n }\n \n+/*\n+ * regarray.\n+ *\n+ * regarray NAME size SIZE\n+ */\n+struct regarray_spec {\n+\tchar *name;\n+\tuint32_t size;\n+};\n+\n+static void\n+regarray_spec_free(struct regarray_spec *s)\n+{\n+\tif (!s)\n+\t\treturn;\n+\n+\tfree(s->name);\n+\ts->name = NULL;\n+}\n+\n+static int\n+regarray_statement_parse(struct regarray_spec *s,\n+\t\t\t char **tokens,\n+\t\t\t uint32_t n_tokens,\n+\t\t\t uint32_t n_lines,\n+\t\t\t uint32_t *err_line,\n+\t\t\t const char **err_msg)\n+{\n+\tchar *p;\n+\n+\t/* Check format. */\n+\tif ((n_tokens != 4) || strcmp(tokens[2], \"size\")) {\n+\t\tif (err_line)\n+\t\t\t*err_line = n_lines;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Invalid regarray statement.\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* spec. */\n+\ts->name = strdup(tokens[1]);\n+\tif (!s->name) {\n+\t\tif (err_line)\n+\t\t\t*err_line = n_lines;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tp = tokens[3];\n+\ts->size = strtoul(p, &p, 0);\n+\tif (p[0] || !s->size) {\n+\t\tif (err_line)\n+\t\t\t*err_line = n_lines;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Invalid size argument.\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n /*\n  * apply.\n  *\n@@ -1066,6 +1128,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \tstruct metadata_spec metadata_spec = {0};\n \tstruct action_spec action_spec = {0};\n \tstruct table_spec table_spec = {0};\n+\tstruct regarray_spec regarray_spec = {0};\n \tstruct apply_spec apply_spec = {0};\n \tuint32_t n_lines;\n \tuint32_t block_mask = 0;\n@@ -1405,6 +1468,33 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\tcontinue;\n \t\t}\n \n+\t\t/* regarray. */\n+\t\tif (!strcmp(tokens[0], \"regarray\")) {\n+\t\t\tstatus = regarray_statement_parse(&regarray_spec,\n+\t\t\t\t\t\t\t  tokens,\n+\t\t\t\t\t\t\t  n_tokens,\n+\t\t\t\t\t\t\t  n_lines,\n+\t\t\t\t\t\t\t  err_line,\n+\t\t\t\t\t\t\t  err_msg);\n+\t\t\tif (status)\n+\t\t\t\tgoto error;\n+\n+\t\t\tstatus = rte_swx_pipeline_regarray_config(p,\n+\t\t\t\tregarray_spec.name,\n+\t\t\t\tregarray_spec.size);\n+\t\t\tif (status) {\n+\t\t\t\tif (err_line)\n+\t\t\t\t\t*err_line = n_lines;\n+\t\t\t\tif (err_msg)\n+\t\t\t\t\t*err_msg = \"Register array configuration error.\";\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\tregarray_spec_free(&regarray_spec);\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\t/* apply. */\n \t\tif (!strcmp(tokens[0], \"apply\")) {\n \t\t\tstatus = apply_statement_parse(&block_mask,\n@@ -1457,6 +1547,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \tmetadata_spec_free(&metadata_spec);\n \taction_spec_free(&action_spec);\n \ttable_spec_free(&table_spec);\n+\tregarray_spec_free(&regarray_spec);\n \tapply_spec_free(&apply_spec);\n \treturn status;\n }\ndiff --git a/lib/librte_pipeline/version.map b/lib/librte_pipeline/version.map\nindex 87c826f1b..26a9edf47 100644\n--- a/lib/librte_pipeline/version.map\n+++ b/lib/librte_pipeline/version.map\n@@ -102,4 +102,10 @@ EXPERIMENTAL {\n \trte_swx_pipeline_table_state_get;\n \trte_swx_pipeline_table_state_set;\n \trte_swx_pipeline_table_type_register;\n+\n+\t#added in 21.05\n+\trte_swx_ctl_pipeline_regarray_read;\n+\trte_swx_ctl_pipeline_regarray_write;\n+\trte_swx_ctl_regarray_info_get;\n+\trte_swx_pipeline_regarray_config;\n };\n",
    "prefixes": []
}